// Copyright (c) 2019 IoTeX Foundation
// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
// This source code is governed by Apache License 2.0 that can be found in the LICENSE file.

package blockchain

import (
	"encoding/hex"
	"math/big"
	"time"

	"github.com/iotexproject/go-pkgs/crypto"
	"github.com/iotexproject/iotex-address/address"
	"github.com/pkg/errors"
)

const (
	// StableTokenID is the ID of StableToken
	StableTokenID = "0000000000000000"
	// StableTokenBinary is the binary code of StableToken
	StableTokenBinary = "60806040526000600660006101000a81548160ff021916908315150217905550600060075560006008556040805190810160405280600781526020017f54727565434e5900000000000000000000000000000000000000000000000000815250600a90805190602001906200007692919062000187565b506040805190810160405280600481526020017f434e595400000000000000000000000000000000000000000000000000000000815250600b9080519060200190620000c492919062000187565b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a362000236565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620001ca57805160ff1916838001178555620001fb565b82800160010185558215620001fb579182015b82811115620001fa578251825591602001919060010190620001dd565b5b5090506200020a91906200020e565b5090565b6200023391905b808211156200022f57600081600090555060010162000215565b5090565b90565b61442680620002466000396000f30060806040526004361061021a576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806302d3fdc91461021f57806306aa9bd11461024a57806306fdde031461027b578063070485a91461030b578063095ea7b31461034e578063121d8fdd146103b3578063158ef93e146103e657806318160ddd1461041557806323b872dd146104405780632aed7f3f146104c55780632e0f2625146105085780632e44040314610539578063313ce5671461056a5780633ed10b921461059b5780633f4ba83a146105f257806340c10f191461060957806342966c6814610656578063520060501461068357806354f78dad146106ba5780635c131d70146107155780635c975abb14610740578063661884631461076f57806370a08231146107d4578063715018a61461082b5780637b103999146108425780637bb98a681461089957806380da0410146108f0578063833099a4146109235780638456cb591461095657806388ee39cc1461096d5780638da5cb5b146109d05780638f32d59b14610a2757806395d89b4114610a56578063a9059cbb14610ae6578063a91ee0dc14610b4b578063b5644d7614610b8e578063bd7243f614610bb9578063d73dd62314610bfc578063dd62ed3e14610c61578063e30c397814610cd8578063edc1e4f914610d2f578063ef286e9614610d8a578063f12d54d814610dcb578063f2fde38b14610e22575b600080fd5b34801561022b57600080fd5b50610234610e65565b6040518082815260200191505060405180910390f35b34801561025657600080fd5b5061025f610e6b565b604051808260ff1660ff16815260200191505060405180910390f35b34801561028757600080fd5b50610290610e70565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102d05780820151818401526020810190506102b5565b50505050905090810190601f1680156102fd5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561031757600080fd5b5061034c600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610f0e565b005b34801561035a57600080fd5b50610399600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610fa8565b604051808215151515815260200191505060405180910390f35b3480156103bf57600080fd5b506103c8610fbf565b60405180826000191660001916815260200191505060405180910390f35b3480156103f257600080fd5b506103fb610fe3565b604051808215151515815260200191505060405180910390f35b34801561042157600080fd5b5061042a610ff6565b6040518082815260200191505060405180910390f35b34801561044c57600080fd5b506104ab600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611000565b604051808215151515815260200191505060405180910390f35b3480156104d157600080fd5b50610506600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611019565b005b34801561051457600080fd5b5061051d6110e9565b604051808260ff1660ff16815260200191505060405180910390f35b34801561054557600080fd5b5061054e6110ee565b604051808260ff1660ff16815260200191505060405180910390f35b34801561057657600080fd5b5061057f6110f7565b604051808260ff1660ff16815260200191505060405180910390f35b3480156105a757600080fd5b506105b0611100565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156105fe57600080fd5b50610607611126565b005b34801561061557600080fd5b50610654600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611206565b005b34801561066257600080fd5b50610681600480360381019080803590602001909291905050506113f3565b005b34801561068f57600080fd5b506106b86004803603810190808035906020019092919080359060200190929190505050611400565b005b3480156106c657600080fd5b506106fb600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506114dc565b604051808215151515815260200191505060405180910390f35b34801561072157600080fd5b5061072a611678565b6040518082815260200191505060405180910390f35b34801561074c57600080fd5b5061075561167e565b604051808215151515815260200191505060405180910390f35b34801561077b57600080fd5b506107ba600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611691565b604051808215151515815260200191505060405180910390f35b3480156107e057600080fd5b50610815600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506116a8565b6040518082815260200191505060405180910390f35b34801561083757600080fd5b506108406117a9565b005b34801561084e57600080fd5b5061085761187b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156108a557600080fd5b506108ae6118a1565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156108fc57600080fd5b506109056118c7565b60405180826000191660001916815260200191505060405180910390f35b34801561092f57600080fd5b506109386118eb565b60405180826000191660001916815260200191505060405180910390f35b34801561096257600080fd5b5061096b61190f565b005b34801561097957600080fd5b506109ce600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506119f0565b005b3480156109dc57600080fd5b506109e5611bc1565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610a3357600080fd5b50610a3c611bea565b604051808215151515815260200191505060405180910390f35b348015610a6257600080fd5b50610a6b611c41565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610aab578082015181840152602081019050610a90565b50505050905090810190601f168015610ad85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b348015610af257600080fd5b50610b31600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611cdf565b604051808215151515815260200191505060405180910390f35b348015610b5757600080fd5b50610b8c600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611cf6565b005b348015610b9a57600080fd5b50610ba3611db2565b6040518082815260200191505060405180910390f35b348015610bc557600080fd5b50610bfa600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611db8565b005b348015610c0857600080fd5b50610c47600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050612125565b604051808215151515815260200191505060405180910390f35b348015610c6d57600080fd5b50610cc2600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061213c565b6040518082815260200191505060405180910390f35b348015610ce457600080fd5b50610ced612272565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610d3b57600080fd5b50610d70600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612298565b604051808215151515815260200191505060405180910390f35b348015610d9657600080fd5b50610db560048036038101908080359060200190929190505050612434565b6040518082815260200191505060405180910390f35b348015610dd757600080fd5b50610de0612457565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610e2e57600080fd5b50610e63600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061247d565b005b60075481565b600281565b600a8054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610f065780601f10610edb57610100808354040283529160200191610f06565b820191906000526020600020905b815481529060010190602001808311610ee957829003601f168201915b505050505081565b610f16611bea565b1515610f2157600080fd5b80600660016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167f290f819019b4cd5b81e011b32265572a8dfa09a7d475f2933b886831f7f93ddd60405160405180910390a250565b6000610fb583833361249c565b6001905092915050565b7f63616e4275726e0000000000000000000000000000000000000000000000000081565b600260149054906101000a900460ff1681565b6000600554905090565b600061100e848484336125cf565b600190509392505050565b611021611bea565b151561102c57600080fd5b8073ffffffffffffffffffffffffffffffffffffffff1663f2fde38b611050611bc1565b6040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b1580156110ce57600080fd5b505af11580156110e2573d6000803e3d6000fd5b5050505050565b606481565b60006002905090565b60006064905090565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61112e611bea565b151561113957600080fd5b600660009054906101000a900460ff1615156111bd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f546f6b656e204e6f74205061757365640000000000000000000000000000000081525060200191505060405180910390fd5b6000600660006101000a81548160ff0219169083151502179055507fbfc7b47e079b745ec7404d7fc82a0635e2a8363341743448b3bcf3f79ad59d0460405160405180910390a1565b61120e611bea565b151561121957600080fd5b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c2ab66dd837f6861735061737365644b59432f414d4c000000000000000000000000000000007f6973426c61636b6c6973746564000000000000000000000000000000000000006040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001836000191660001916815260200182600019166000191681526020019350505050602060405180830381600087803b15801561133657600080fd5b505af115801561134a573d6000803e3d6000fd5b505050506040513d602081101561136057600080fd5b810190808051906020019092919050505015156113e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f5f746f2063616e6e6f74206d696e74000000000000000000000000000000000081525060200191505060405180910390fd5b6113ef828261277e565b5050565b6113fd33826129e6565b50565b611408611bea565b151561141357600080fd5b80821115151561148b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260098152602001807f6d696e203e206d6178000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b81600781905550806008819055507f21d54a4c1f750b4f93779e3e8b4de89db3f31bab8f203e68569727fee906cc328282604051808381526020018281526020019250505060405180910390a15050565b60006114e6611bea565b15156114f157600080fd5b81600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156115b857600080fd5b505af11580156115cc573d6000803e3d6000fd5b505050506040513d60208110156115e257600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614151561162c57600080fd5b8173ffffffffffffffffffffffffffffffffffffffff167fa89fb8ab3845cb6919c98b54ca0d8f398df48c64ae04ed309cd7b130539badd460405160405180910390a260019050919050565b60085481565b600660009054906101000a900460ff1681565b600061169e8383336129f4565b6001905092915050565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231836040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561176757600080fd5b505af115801561177b573d6000803e3d6000fd5b505050506040513d602081101561179157600080fd5b81019080805190602001909291905050509050919050565b6117b1611bea565b15156117bc57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b7f6861735061737365644b59432f414d4c0000000000000000000000000000000081565b7f6973426c61636b6c69737465640000000000000000000000000000000000000081565b611917611bea565b151561192257600080fd5b600660009054906101000a900460ff161515156119a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600c8152602001807f546f6b656e20506175736564000000000000000000000000000000000000000081525060200191505060405180910390fd5b6001600660006101000a81548160ff0219169083151502179055507f4d7c2d647163ffee415429ee44043a4e5252a64365083793b624b51dfd7ce01d60405160405180910390a1565b60006119fa611bea565b1515611a0557600080fd5b8273ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015611aa057600080fd5b505af1158015611ab4573d6000803e3d6000fd5b505050506040513d6020811015611aca57600080fd5b810190808051906020019092919050505090508273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb83836040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015611b8057600080fd5b505af1158015611b94573d6000803e3d6000fd5b505050506040513d6020811015611baa57600080fd5b810190808051906020019092919050505050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b600b8054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015611cd75780601f10611cac57610100808354040283529160200191611cd7565b820191906000526020600020905b815481529060010190602001808311611cba57829003601f168201915b505050505081565b6000611cec338484612b27565b6001905092915050565b611cfe611bea565b1515611d0957600080fd5b80600960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f278c70ced5f3e0e5eeb385b5ff9cb735748ba00a625147e66065ed48fc1562cd60405160405180910390a250565b600d5481565b6000611dc2611bea565b1515611dcd57600080fd5b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637338c25c837f6973426c61636b6c6973746564000000000000000000000000000000000000006040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001826000191660001916815260200192505050602060405180830381600087803b158015611eba57600080fd5b505af1158015611ece573d6000803e3d6000fd5b505050506040513d6020811015611ee457600080fd5b81019080805190602001909291905050501515611f69576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f5f6163636f756e74206973206e6f7420626c61636b6c6973746564000000000081525060200191505060405180910390fd5b611f72826116a8565b9050600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e30443bc8360006040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b15801561203a57600080fd5b505af115801561204e573d6000803e3d6000fd5b5050505061206781600554612d0890919063ffffffff16565b6005819055508173ffffffffffffffffffffffffffffffffffffffff167ffa8f14973a436f651cdc72fcb50527f364a3b92681dc7aacb0ebeed1e7fb7070826040518082815260200191505060405180910390a2600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b6000612132838333612d29565b6001905092915050565b6000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631a46ec8284846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600087803b15801561222f57600080fd5b505af1158015612243573d6000803e3d6000fd5b505050506040513d602081101561225957600080fd5b8101908080519060200190929190505050905092915050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006122a2611bea565b15156122ad57600080fd5b81600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561237457600080fd5b505af1158015612388573d6000803e3d6000fd5b505050506040513d602081101561239e57600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff161415156123e857600080fd5b8173ffffffffffffffffffffffffffffffffffffffff167fb02601a43e72e0ac747eb6d02226aec79064038d7ce3db3e633b1e769c5ed3bb60405160405180910390a260019050919050565b600c8181548110151561244357fe5b906000526020600020016000915090505481565b600660019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b612485611bea565b151561249057600080fd5b61249981612e5c565b50565b600660009054906101000a900460ff16151515612521576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600c8152602001807f546f6b656e20506175736564000000000000000000000000000000000000000081525060200191505060405180910390fd5b600660019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637d6a5f7b6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401600060405180830381600087803b1580156125a757600080fd5b505af11580156125bb573d6000803e3d6000fd5b505050506125ca838383612f56565b505050565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637338c25c827f6973426c61636b6c6973746564000000000000000000000000000000000000006040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001826000191660001916815260200192505050602060405180830381600087803b1580156126bc57600080fd5b505af11580156126d0573d6000803e3d6000fd5b505050506040513d60208110156126e657600080fd5b810190808051906020019092919050505015151561276c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260178152602001807f5f7370656e64657220697320626c61636b6c697374656400000000000000000081525060200191505060405180910390fd5b612778848484846130d1565b50505050565b612786611bea565b151561279157600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614151515612836576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f746f20616464726573732063616e6e6f74206265207a65726f0000000000000081525060200191505060405180910390fd5b61284b8160055461320690919063ffffffff16565b600581905550600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166321e5383a83836040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b15801561291657600080fd5b505af115801561292a573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff167f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885826040518082815260200191505060405180910390a28173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b6129f08282613227565b5050565b600660009054906101000a900460ff16151515612a79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600c8152602001807f546f6b656e20506175736564000000000000000000000000000000000000000081525060200191505060405180910390fd5b600660019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637d6a5f7b6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401600060405180830381600087803b158015612aff57600080fd5b505af1158015612b13573d6000803e3d6000fd5b50505050612b22838383613401565b505050565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b901943784847f6973426c61636b6c6973746564000000000000000000000000000000000000006040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182600019166000191681526020019350505050602060405180830381600087803b158015612c4857600080fd5b505af1158015612c5c573d6000803e3d6000fd5b505050506040513d6020811015612c7257600080fd5b8101908080519060200190929190505050151515612cf8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600b8152602001807f626c61636b6c697374656400000000000000000000000000000000000000000081525060200191505060405180910390fd5b612d038383836138f8565b505050565b600080838311151515612d1a57600080fd5b82840390508091505092915050565b600660009054906101000a900460ff16151515612dae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600c8152602001807f546f6b656e20506175736564000000000000000000000000000000000000000081525060200191505060405180910390fd5b600660019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637d6a5f7b6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401600060405180830381600087803b158015612e3457600080fd5b505af1158015612e48573d6000803e3d6000fd5b50505050612e57838383613a2b565b505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151515612e9857600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663da46098c8285856040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050600060405180830381600087803b15801561304f57600080fd5b505af1158015613063573d6000803e3d6000fd5b505050508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a3505050565b600660009054906101000a900460ff16151515613156576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600c8152602001807f546f6b656e20506175736564000000000000000000000000000000000000000081525060200191505060405180910390fd5b600660019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637d6a5f7b6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401600060405180830381600087803b1580156131dc57600080fd5b505af11580156131f0573d6000803e3d6000fd5b5050505061320084848484613cd1565b50505050565b600080828401905083811015151561321d57600080fd5b8091505092915050565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c2ab66dd837f63616e4275726e000000000000000000000000000000000000000000000000007f6973426c61636b6c6973746564000000000000000000000000000000000000006040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001836000191660001916815260200182600019166000191681526020019350505050602060405180830381600087803b15801561334457600080fd5b505af1158015613358573d6000803e3d6000fd5b505050506040513d602081101561336e57600080fd5b810190808051906020019092919050505015156133f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f5f6275726e65722063616e6e6f74206275726e0000000000000000000000000081525060200191505060405180910390fd5b6133fd8282613df3565b5050565b6000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631a46ec8283866040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600087803b1580156134f457600080fd5b505af1158015613508573d6000803e3d6000fd5b505050506040513d602081101561351e57600080fd5b810190808051906020019092919050505090508083111561365057600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663da46098c838660006040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050600060405180830381600087803b15801561363357600080fd5b505af1158015613647573d6000803e3d6000fd5b50505050613762565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166397d88cd28386866040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050600060405180830381600087803b15801561374957600080fd5b505af115801561375d573d6000803e3d6000fd5b505050505b8373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631a46ec8286896040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600087803b1580156138a257600080fd5b505af11580156138b6573d6000803e3d6000fd5b505050506040513d60208110156138cc57600080fd5b81019080805190602001909291905050506040518082815260200191505060405180910390a350505050565b600660009054906101000a900460ff1615151561397d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600c8152602001807f546f6b656e20506175736564000000000000000000000000000000000000000081525060200191505060405180910390fd5b600660019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637d6a5f7b6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401600060405180830381600087803b158015613a0357600080fd5b505af1158015613a17573d6000803e3d6000fd5b50505050613a26838383613ef5565b505050565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635fd72d168285856040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050600060405180830381600087803b158015613b2457600080fd5b505af1158015613b38573d6000803e3d6000fd5b505050508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631a46ec8285886040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600087803b158015613c7c57600080fd5b505af1158015613c90573d6000803e3d6000fd5b505050506040513d6020811015613ca657600080fd5b81019080805190602001909291905050506040518082815260200191505060405180910390a3505050565b613cdc848484612b27565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166397d88cd28583856040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050600060405180830381600087803b158015613dd557600080fd5b505af1158015613de9573d6000803e3d6000fd5b5050505050505050565b6007548110151515613e6d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f62656c6f77206d696e206275726e20626f756e6400000000000000000000000081525060200191505060405180910390fd5b6008548111151515613ee7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f65786365656473206d6178206275726e20626f756e640000000000000000000081525060200191505060405180910390fd5b613ef18282614119565b5050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663cf8eeb7e84836040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b158015613fba57600080fd5b505af1158015613fce573d6000803e3d6000fd5b50505050600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166321e5383a83836040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b15801561409757600080fd5b505af11580156140ab573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b600660009054906101000a900460ff1615151561419e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600c8152602001807f546f6b656e20506175736564000000000000000000000000000000000000000081525060200191505060405180910390fd5b600660019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637d6a5f7b6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401600060405180830381600087803b15801561422457600080fd5b505af1158015614238573d6000803e3d6000fd5b50505050614246828261424a565b5050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663cf8eeb7e83836040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b15801561430f57600080fd5b505af1158015614323573d6000803e3d6000fd5b5050505061433c81600554612d0890919063ffffffff16565b6005819055508173ffffffffffffffffffffffffffffffffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5826040518082815260200191505060405180910390a2600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a350505600a165627a7a7230582080a577904ae90ef14f7083e309f9adb47a57e963194ada53b74b26ed49a6f2b30029"
	// AllowanceSheetID is the ID of AllowanceSheet
	AllowanceSheetID = "0000000000000001"
	// AllowanceSheetBinary is the binary of AllowanceSheet
	AllowanceSheetBinary = "6080604052336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3610916806100cf6000396000f30060806040526004361061008e576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680631a46ec82146100935780635fd72d161461010a578063715018a6146101775780638da5cb5b1461018e5780638f32d59b146101e557806397d88cd214610214578063da46098c14610281578063f2fde38b146102ee575b600080fd5b34801561009f57600080fd5b506100f4600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610331565b6040518082815260200191505060405180910390f35b34801561011657600080fd5b50610175600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610356565b005b34801561018357600080fd5b5061018c61047d565b005b34801561019a57600080fd5b506101a361054f565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156101f157600080fd5b506101fa610578565b604051808215151515815260200191505060405180910390f35b34801561022057600080fd5b5061027f600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506105cf565b005b34801561028d57600080fd5b506102ec600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506106f6565b005b3480156102fa57600080fd5b5061032f600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061078f565b005b6001602052816000526040600020602052806000526040600020600091509150505481565b61035e610578565b151561036957600080fd5b6103f881600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546107ae90919063ffffffff16565b600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505050565b610485610578565b151561049057600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b6105d7610578565b15156105e257600080fd5b61067181600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546107cf90919063ffffffff16565b600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505050565b6106fe610578565b151561070957600080fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505050565b610797610578565b15156107a257600080fd5b6107ab816107f0565b50565b60008082840190508381101515156107c557600080fd5b8091505092915050565b6000808383111515156107e157600080fd5b82840390508091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561082c57600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505600a165627a7a72305820ac78e8ec74fc698fa46ab46be26464c7fbd5c6458cdf2bf3cf9841eb5b6157480029"
	// BalanceSheetID is the ID of BalanceSheet
	BalanceSheetID = "0000000000000002"
	// BalanceSheetBinary is the binary of BalanceSheet
	BalanceSheetBinary = "6080604052336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3610755806100cf6000396000f30060806040526004361061008e576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806321e5383a1461009357806370a08231146100e0578063715018a6146101375780638da5cb5b1461014e5780638f32d59b146101a5578063cf8eeb7e146101d4578063e30443bc14610221578063f2fde38b1461026e575b600080fd5b34801561009f57600080fd5b506100de600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506102b1565b005b3480156100ec57600080fd5b50610121600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061035d565b6040518082815260200191505060405180910390f35b34801561014357600080fd5b5061014c610375565b005b34801561015a57600080fd5b50610163610447565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156101b157600080fd5b506101ba610470565b604051808215151515815260200191505060405180910390f35b3480156101e057600080fd5b5061021f600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506104c7565b005b34801561022d57600080fd5b5061026c600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610573565b005b34801561027a57600080fd5b506102af600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506105ce565b005b6102b9610470565b15156102c457600080fd5b61031681600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546105ed90919063ffffffff16565b600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505050565b60016020528060005260406000206000915090505481565b61037d610470565b151561038857600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b6104cf610470565b15156104da57600080fd5b61052c81600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461060e90919063ffffffff16565b600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505050565b61057b610470565b151561058657600080fd5b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505050565b6105d6610470565b15156105e157600080fd5b6105ea8161062f565b50565b600080828401905083811015151561060457600080fd5b8091505092915050565b60008083831115151561062057600080fd5b82840390508091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561066b57600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505600a165627a7a72305820cbfc2e707efe913a165253405c1af8eccb6b46b44361b5ac904e7d71c0ed11e90029"
	// RegistryID is the ID of Registry
	RegistryID = "0000000000000003"
	// RegistryBinary is the binary of Registry
	RegistryBinary = "6080604052336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36110ee806100cf6000396000f3006080604052600436106100e6576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063163f6691146100eb5780635f141a0f146101995780636ca0607214610202578063715018a614610293578063719d0d30146102aa57806371b6d6ea146103585780637338c25c146103bd5780638278337a146104265780638da5cb5b146104735780638f32d59b146104ca578063b9019437146104f9578063c2ab66dd14610582578063def81479146105f9578063e23c50631461062c578063f2fde38b14610691578063fdac9ff7146106d4575b600080fd5b3480156100f757600080fd5b5061013a600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803560001916906020019092919050505061072f565b6040518085815260200184600019166000191681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200194505050505060405180910390f35b3480156101a557600080fd5b506101e86004803603810190808035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610845565b604051808215151515815260200191505060405180910390f35b34801561020e57600080fd5b50610251600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190505050610941565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561029f57600080fd5b506102a86109c7565b005b3480156102b657600080fd5b506102f9600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190505050610a99565b6040518085815260200184600019166000191681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200194505050505060405180910390f35b34801561036457600080fd5b506103a7600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190505050610af6565b6040518082815260200191505060405180910390f35b3480156103c957600080fd5b5061040c600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190505050610b5c565b604051808215151515815260200191505060405180910390f35b34801561043257600080fd5b506104556004803603810190808035600019169060200190929190505050610bc5565b60405180826000191660001916815260200191505060405180910390f35b34801561047f57600080fd5b50610488610c7a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156104d657600080fd5b506104df610ca3565b604051808215151515815260200191505060405180910390f35b34801561050557600080fd5b50610568600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190505050610cfa565b604051808215151515815260200191505060405180910390f35b34801561058e57600080fd5b506105df600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080356000191690602001909291908035600019169060200190929190505050610d21565b604051808215151515815260200191505060405180910390f35b34801561060557600080fd5b5061060e610d49565b60405180826000191660001916815260200191505060405180910390f35b34801561063857600080fd5b5061067b600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190505050610d6d565b6040518082815260200191505060405180910390f35b34801561069d57600080fd5b506106d2600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610dd3565b005b3480156106e057600080fd5b5061072d600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803560001916906020019092919080359060200190929190505050610df2565b005b60008060008061073d611080565b600160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000876000191660001916815260200190815260200160002060806040519081016040529081600082015481526020016001820154600019166000191681526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016003820154815250509050806000015181602001518260400151836060015194509450945094505092959194509250565b600061084f610c7a565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161480610939575061093882847f63616e5772697465322d00000000000000000000000000000000000000000000186040516020018082600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310151561090657805182526020820191506020810190506020830392506108e1565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020610b5c565b5b905092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000836000191660001916815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905092915050565b6109cf610ca3565b15156109da57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b6001602052816000526040600020602052806000526040600020600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154905084565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000836000191660001916815260200190815260200160002060030154905092915050565b600080600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008460001916600019168152602001908152602001600020600001541415905092915050565b6000817f63616e5772697465322d00000000000000000000000000000000000000000000186040516020018082600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083101515610c465780518252602082019150602081019050602083039250610c21565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209050919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b6000610d068483610b5c565b8015610d185750610d178383610b5c565b5b90509392505050565b6000610d2d8484610b5c565b8015610d405750610d3e8483610b5c565b155b90509392505050565b7f63616e5772697465322d0000000000000000000000000000000000000000000081565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000836000191660001916815260200190815260200160002060000154905092915050565b610ddb610ca3565b1515610de657600080fd5b610def81610f86565b50565b610dfc8233610845565b1515610e0757600080fd5b608060405190810160405280828152602001600080191681526020013373ffffffffffffffffffffffffffffffffffffffff16815260200142815250600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008460001916600019168152602001908152602001600020600082015181600001556020820151816001019060001916905560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550606082015181600301559050503373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f7f467fc85b3c9db1144a5f705bcb37dcd17e760ed57b1921186f50b51000c3a184846040518083600019166000191681526020018281526020016020019250505060405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151515610fc257600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6080604051908101604052806000815260200160008019168152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815250905600a165627a7a72305820a1123c3f31e8c36798fc6b6ebdf5ce06227837c3bd5a7cceeaf6503ab52654910029"
	// GlobalPauseID is the ID of GlobalPause
	GlobalPauseID = "0000000000000004"
	// GlobalPauseBinary is the binary of GlobalPause
	GlobalPauseBinary = "608060405260008060146101000a81548160ff021916908315150217905550336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36107ce806100e96000396000f30060806040526004361061008e576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632ad0a4e914610093578063715018a6146101235780637d6a5f7b1461013a5780638da5cb5b146101515780638f32d59b146101a8578063d06a57b0146101d7578063e1d4cf1f1461024c578063f2fde38b1461027b575b600080fd5b34801561009f57600080fd5b506100a86102be565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100e85780820151818401526020810190506100cd565b50505050905090810190601f1680156101155780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561012f57600080fd5b5061013861035c565b005b34801561014657600080fd5b5061014f61042e565b005b34801561015d57600080fd5b50610166610509565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156101b457600080fd5b506101bd610532565b604051808215151515815260200191505060405180910390f35b3480156101e357600080fd5b5061024a600480360381019080803515159060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610589565b005b34801561025857600080fd5b506102616105d1565b604051808215151515815260200191505060405180910390f35b34801561028757600080fd5b506102bc600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506105e4565b005b60018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156103545780601f1061032957610100808354040283529160200191610354565b820191906000526020600020905b81548152906001019060200180831161033757829003601f168201915b505050505081565b610364610532565b151561036f57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b600060149054906101000a900460ff16156001901515610506576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252838181546001816001161561010002031660029004815260200191508054600181600116156101000203166002900480156104f75780601f106104cc576101008083540402835291602001916104f7565b820191906000526020600020905b8154815290600101906020018083116104da57829003601f168201915b50509250505060405180910390fd5b50565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b610591610532565b151561059c57600080fd5b81600060146101000a81548160ff02191690831515021790555080600190805190602001906105cc9291906106fd565b505050565b600060149054906101000a900460ff1681565b6105ec610532565b15156105f757600080fd5b61060081610603565b50565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561063f57600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061073e57805160ff191683800117855561076c565b8280016001018555821561076c579182015b8281111561076b578251825591602001919060010190610750565b5b509050610779919061077d565b5090565b61079f91905b8082111561079b576000816000905550600101610783565b5090565b905600a165627a7a7230582061464672f64d91fff08b2a167e40f72464a947d261ae29dcebaabd1eeb390c7c0029"
	// StartStableTokenID is the ID of StartStableToken
	StartStableTokenID = "0000000000000005"
)

type (
	// StableToken is an interface for a stable token
	StableToken interface {
		Contract
		Mint(string, int64) (string, error)
		Burn(string, string, string, int64) (string, error)
		Transfer(string, int64) (string, error)

		MintWhitelist() []byte
		BurnWhiteList() []byte

		SetAllowance(string) StableToken
		SetBalance(string) StableToken
		SetRegistry(string) StableToken
		SetPause(string) StableToken
		SetStable(string) StableToken
	}

	stableToken struct {
		Contract
		allowance       string // address of allowance sheet
		balance         string // address of balance sheet
		registry        string // address of registry
		pause           string // address of global pause
		stable          string // address of stable token
		kycAmlWhitelist []byte
		burnWhitelist   []byte
	}
)

// NewStableToken creates a new Stable Token
func NewStableToken(exp string) StableToken {
	return &stableToken{Contract: NewContract(exp)}
}

func (s *stableToken) Mint(bech32 string, amount int64) (string, error) {
	addr, err := address.FromString(bech32)
	if err != nil {
		return "", errors.Wrap(err, "failed to issue stable token")
	}
	if len(addr.Bytes()) != 20 {
		return "", errors.Wrap(crypto.ErrInvalidKey, "failed to issue stable token")
	}

	if len(s.kycAmlWhitelist) == 0 {
		// get the KYC whitelist token
		res, err := s.RunAsOwner().SetAddress(s.stable).Read("80da0410", nil)
		if err != nil {
			return "", errors.Wrap(err, "failed to get KYC whitelist")
		}
		s.kycAmlWhitelist, err = hex.DecodeString(res)
		if err != nil {
			return "", errors.Wrapf(err, "invalid KYC whitelist")
		}
		if len(s.kycAmlWhitelist) != 32 {
			return "", errors.Errorf("invalid KYC whitelist length = %d, expecting 32", len(s.kycAmlWhitelist))
		}
	}

	// add address to KYC whitelist
	h, err := s.RunAsOwner().SetAddress(s.registry).Call("fdac9ff7", addr.Bytes(), s.kycAmlWhitelist, []byte{1})
	if err != nil {
		return h, errors.Wrap(err, "failed to add address to KYC whitelist")
	}
	time.Sleep(time.Millisecond * 100)

	// mint stable token
	h1, err := s.SetAddress(s.stable).Call("40c10f19", addr.Bytes(), big.NewInt(amount).Bytes())
	if err != nil {
		return h1, errors.Wrap(err, "call failed to issue stable token")
	}

	if _, err := s.CheckCallResult(h); err != nil {
		return h, errors.Wrap(err, "check failed to add address to KYC whitelist")
	}
	if _, err = s.CheckCallResult(h1); err != nil {
		return h1, errors.Wrap(err, "check failed to issue stable token")
	}
	return h1, nil
}

func (s *stableToken) Burn(bech32, pubkey, prvkey string, amount int64) (string, error) {
	addr, err := address.FromString(bech32)
	if err != nil {
		return "", errors.Wrap(err, "failed to redeem stable token")
	}
	if len(addr.Bytes()) != 20 {
		return "", errors.Wrap(crypto.ErrInvalidKey, "failed to redeem stable token")
	}

	if len(s.burnWhitelist) == 0 {
		// get the BURN whitelist token
		res, err := s.RunAsOwner().SetAddress(s.stable).Read("121d8fdd", nil)
		if err != nil {
			return "", errors.Wrap(err, "failed to get BURN whitelist")
		}
		s.burnWhitelist, err = hex.DecodeString(res)
		if err != nil {
			return "", errors.Wrapf(err, "invalid BURN whitelist")
		}
		if len(s.burnWhitelist) != 32 {
			return "", errors.Errorf("invalid BURN whitelist length = %d, expecting 32", len(s.burnWhitelist))
		}
	}

	// add address to BURN whitelist
	h, err := s.RunAsOwner().SetAddress(s.registry).Call("fdac9ff7", addr.Bytes(), s.burnWhitelist, []byte{1})
	if err != nil {
		return h, errors.Wrap(err, "failed to add address to BURN whitelist")
	}
	time.Sleep(time.Millisecond * 100)

	// set burn bounds
	h1, err := s.SetAddress(s.stable).Call("52006050", big.NewInt(amount).Bytes(), big.NewInt(amount).Bytes())
	if err != nil {
		return h1, errors.Wrap(err, "failed to set burn bounds")
	}
	time.Sleep(time.Millisecond * 100)

	// redeem stable token
	h2, err := s.SetExecutor(bech32).
		SetPrvKey(prvkey).
		Call("42966c68", big.NewInt(amount).Bytes())
	if err != nil {
		return h2, errors.Wrap(err, "call failed to redeem stable token")
	}

	if _, err := s.CheckCallResult(h); err != nil {
		return h, errors.Wrap(err, "check failed to add address to BURN whitelist")
	}
	if _, err := s.CheckCallResult(h1); err != nil {
		return h1, errors.Wrap(err, "check failed to set burn bounds")
	}
	if _, err := s.CheckCallResult(h2); err != nil {
		return h2, errors.Wrap(err, "check failed to redeem stable token")
	}
	return h2, nil
}

func (s *stableToken) Transfer(string, int64) (string, error) {
	return "", nil
}

// override to return the stable token contract address
func (s *stableToken) Address() string {
	return s.stable
}

func (s *stableToken) MintWhitelist() []byte {
	return s.kycAmlWhitelist
}
func (s *stableToken) BurnWhiteList() []byte {
	return s.burnWhitelist
}

func (s *stableToken) Start() error {
	addrAllowance, err := address.FromString(s.allowance)
	if err != nil {
		return errors.Errorf("invalid allowance sheet address = %s", s.allowance)
	}
	addrBalance, err := address.FromString(s.balance)
	if err != nil {
		return errors.Errorf("invalid balance sheet address = %s", s.balance)
	}
	addrReg, err := address.FromString(s.registry)
	if err != nil {
		return errors.Errorf("invalid registry contract address = %s", s.registry)
	}
	addrPause, err := address.FromString(s.pause)
	if err != nil {
		return errors.Errorf("invalid global pause contract address = %s", s.pause)
	}
	addrStable, err := address.FromString(s.stable)
	if err != nil {
		return errors.Errorf("invalid stable token contract address = %s", s.stable)
	}

	h, err := s.RunAsOwner().SetAddress(s.allowance).Call("f2fde38b", addrStable.Bytes())
	if err != nil {
		return errors.Wrap(err, "allowance sheet failed to transfer ownership")
	}
	time.Sleep(time.Millisecond * 100)

	h1, err := s.SetAddress(s.balance).Call("f2fde38b", addrStable.Bytes())
	if err != nil {
		return errors.Wrap(err, "balance sheet failed to transfer ownership")
	}
	time.Sleep(time.Millisecond * 100)

	h2, err := s.SetAddress(s.stable).Call("edc1e4f9", addrAllowance.Bytes())
	if err != nil {
		return errors.Wrap(err, "stable token contract failed to set allowance sheet")
	}
	time.Sleep(time.Millisecond * 100)

	h3, err := s.Call("54f78dad", addrBalance.Bytes())
	if err != nil {
		return errors.Wrap(err, "stable token contract failed to set balance sheet")
	}
	time.Sleep(time.Millisecond * 100)

	h4, err := s.Call("a91ee0dc", addrReg.Bytes())
	if err != nil {
		return errors.Wrap(err, "call stable token contract failed to set registry")
	}
	time.Sleep(time.Millisecond * 100)

	h5, err := s.Call("070485a9", addrPause.Bytes())
	if err != nil {
		return errors.Wrap(err, "call stable token contract failed to set global pause")
	}

	if _, err := s.CheckCallResult(h); err != nil {
		return errors.Wrap(err, "check allowance sheet failed to transfer ownership")
	}
	if _, err := s.CheckCallResult(h1); err != nil {
		return errors.Wrap(err, "check balance sheet failed to transfer ownership")
	}
	if _, err := s.CheckCallResult(h2); err != nil {
		return errors.Wrap(err, "check stable token contract failed to set allowance sheet")
	}
	if _, err := s.CheckCallResult(h3); err != nil {
		return errors.Wrap(err, "check stable token contract failed to set balance sheet")
	}
	if _, err := s.CheckCallResult(h4); err != nil {
		return errors.Wrap(err, "check stable token contract failed to set registry")
	}
	if _, err := s.CheckCallResult(h5); err != nil {
		return errors.Wrap(err, "check stable token contract failed to set global pause")
	}
	return nil
}

func (s *stableToken) SetAllowance(alw string) StableToken {
	s.allowance = alw
	return s
}

func (s *stableToken) SetBalance(bal string) StableToken {
	s.balance = bal
	return s
}

func (s *stableToken) SetRegistry(reg string) StableToken {
	s.registry = reg
	return s
}

func (s *stableToken) SetPause(pas string) StableToken {
	s.pause = pas
	return s
}

func (s *stableToken) SetStable(stb string) StableToken {
	s.stable = stb
	return s
}
